package st.learnopengl.apps.light

import glm_.glm
import glm_.mat4x4.Mat4
import glm_.vec3.Vec3
import gln.BufferTarget
import gln.VertexAttrType
import gln.draw.DrawMode
import gln.draw.glDrawArrays
import gln.glClearColor
import gln.glf.VertexAttribute
import gln.identifiers.GlBuffer
import gln.identifiers.GlProgram
import gln.uniform.glUniform
import gln.vertexArray.GlVertexArray
import st.learnopengl.common.App
import st.learnopengl.common.GLUT
import st.learnopengl.common.Resource
import org.lwjgl.opengl.GL11C.*

open class ObjectLight(width: Int, height: Int, title: String)
    : App(width, height, title) {

    private var program: GlProgram? = null
    private var vao: GlVertexArray? = null
    private var vbo: GlBuffer? = null

    private var mvp_location: Int = -1
    private var object_color_location: Int = -1
    private var world_light_color_location: Int = -1
    private var object_type_location: Int = -1

    private lateinit var aPosAttr: VertexAttribute

    private val lightPos = Vec3(1.2f, 2.0f, -1.0f)

    override fun onInit() {
        program = GLUT.createProgram("shaders/light/common_vs.glsl"
            , "shaders/light/am_color_fs.glsl")

        vao = GlVertexArray.gen()
        vao!!.bound {
            vbo = GlBuffer.gen()
            vbo!!.bound(BufferTarget.ARRAY) {
                data(Resource.cube_vertex)
            }
        }

        mvp_location = program!!.getUniformLocation("mvp")
        object_color_location = program!!.getUniformLocation("object_color")
        world_light_color_location = program!!.getUniformLocation("world_light_color")
        object_type_location = program!!.getUniformLocation("object_type")

        aPosAttr = VertexAttribute(0, 3, VertexAttrType.FLOAT, false, 3 * 4, 0)

        glEnable(GL_DEPTH_TEST)
        glClearColor(Vec3(0, 0, 0))
    }

    override fun loop() {

        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)

        val viewMatrix = glm.lookAt(Vec3(0.0f, 1.0f, 4.0f), Vec3(0, 0, 0), Vec3(0.0f, 1.0f, 0.0f))
        val projectMatrix = glm.perspective(glm.radians(60.0f), 4.0f / 3.0f, 0.001f, 1000.0f)

        program!!.use {


            glUniform(object_color_location, Vec3(1.0f, 0.5f, 0.31f))
            glUniform(world_light_color_location, Vec3(1.0f, 1.0f, 1.0f))

            vao!!.bound {
                vbo!!.bind(BufferTarget.ARRAY)
                aPosAttr.enable()
                aPosAttr.pointer()

                /**
                 * draw light source first
                 */
                var lightMatrix = Mat4(1.0f)
                lightMatrix = glm.translate(lightMatrix, lightPos)
                lightMatrix = glm.scale(lightMatrix, Vec3(0.2f))

                val mvp = projectMatrix * viewMatrix * lightMatrix
                glUniform(mvp_location, mvp)

                glUniform(object_type_location, Resource.TYPE.LIGHT_SOURCE.v)

                glDrawArrays(DrawMode.TRIANGLES,36)
            }

            vao!!.bound {
                vbo!!.bind(BufferTarget.ARRAY)
                aPosAttr.enable()
                aPosAttr.pointer()

                /**
                 * draw light source first
                 */
                var modelMatrix = Mat4(1.0f)

                val mvp = projectMatrix * viewMatrix * modelMatrix
                glUniform(mvp_location, mvp)

                glUniform(object_type_location, Resource.TYPE.OBJECT.v)

                glDrawArrays(DrawMode.TRIANGLES,36)
            }

        }
    }

    companion object {

        @JvmStatic
        fun main(args: Array<String>) {
            ObjectLight(1280, 720, "Object Light").run()
        }
    }
}